<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    /*
        1.尾调用
            - 即外部函数的返回值是一个内部函数的返回值
            - 需要满足的条件
                - 代码在严格模式下执行
                - 外部函数的返回值是对尾调用函数的调用
                - 尾调用函数返回后不需要执行额外的逻辑;
                - 尾调用函数不是引用外部函数作用域中自由变量的闭包。
     */
    // 1.1 例子
    function inner() {
    }

    function outer() {
        return inner();
    }


    /*
        1.2 尾调用的例子判断
     */
    /*
        "use strict";
        // 无优化:尾调用没有返回 
        function outerFunction() {
              innerFunction();
        }
        // 无优化:尾调用没有直接返回 
        function outerFunction() {
              let innerFunctionResult = innerFunction();
              return innerFunctionResult;
        }
        // 无优化:尾调用返回后必须转型为字符串 
        function outerFunction() {
        return innerFunction().toString(); }
        // 无优化:尾调用是一个闭包 
        function outerFunction() {
        let foo = 'bar';
        function innerFunction() { return foo; }
              return innerFunction();
            }
            
          下面是几个符合尾调用优化条件的例子:
            "use strict";
        // 有优化:栈帧销毁前执行参数计算 
        function outerFunction(a, b) { return innerFunction(a + b);
        }
        // 有优化:初始返回值不涉及栈帧 
        function outerFunction(a, b) {
              if (a < b) {
                return a;
        }
              return innerFunction(a + b);
            }
        // 有优化:两个内部函数都在尾部 
        function outerFunction(condition) {
              return condition ? innerFunctionA() : innerFunctionB();
        }

     */

    /*
        2.尾调用优化的代码
     */
    let start = Date.now();
    function fib2(n) {
        if (n < 2) {
            return n;
        }
        // 有加号操作,不属于
        return fib2(n - 1) + fib2(n - 2)
    }
    console.log(fib2(43))  // 5103 ,指数级
    let end = Date.now()
    console.log('用时:',end-start)


    /*
        2.1 重构后,符合尾调用
     */

    'use strict'

    // 基础框架
    function fib(n) {
        return fibImpl(0, 1, n)
    }

    // 执行递归
    function fibImpl(a, b, n) {
        if (n === 0) {
            return a;
        }
        return fibImpl(b, a + b, n - 1)
    }

    let startUp = Date.now();
    console.log(fib(1000))  // 1
    let endUp = Date.now();
    console.log('用时:',endUp-startUp)

</script>
</body>
</html>